#pragma once
#include <iostream>
#include <vector>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <string>
using std::string;
using std::vector;
#define DEFAULT_BUFFER_SIZE 1024
class Buffer
{
private:
    uint64_t _reader_idx;
    uint64_t _writer_idx;
    vector<char> _buffer;

private:
    char *Begin()
    {
        return &*_buffer.begin();
    }

public:
    Buffer() : _reader_idx(0), _writer_idx(0), _buffer(DEFAULT_BUFFER_SIZE) {}
    char *GetWritePosition() { return Begin() + _writer_idx; }
    char *GetReadPosition() { return Begin() + _reader_idx; }
    uint64_t GetTailIdleSize() { return _buffer.size() - _writer_idx; }
    uint64_t GetHeadIdleSize() { return _reader_idx; }
    uint64_t GetReadAbleSize() { return _writer_idx - _reader_idx; }
    void MoveReadOffset(uint64_t len)
    {
        if (len == 0)
        {
            return;
        }
        assert(len < GetReadAbleSize());
        _reader_idx += len;
    }
    void MoveWriteOffset(uint64_t len)
    {
        assert(len <= GetTailIdleSize());
        _writer_idx += len;
    }
    void EnsureWriteSpace(uint64_t len)
    {
        if (GetTailIdleSize() >= len)
        {
            return;
        }
        if (len <= GetHeadIdleSize() + GetTailIdleSize()) // 字节长度小于前面空闲加上后面空闲，就把读空间移动到前面去
        {
            uint64_t rdx = GetReadAbleSize();
            std::copy(GetReadPosition(), GetReadPosition() + rdx, Begin());
            _reader_idx = 0;
            _writer_idx = rdx;
            return;
        }
        // 走到这里说明是真的没空间了，得扩容
        _buffer.resize(_writer_idx + len);
        return;
    }
    void Write(const void *data, uint64_t len)
    {
        // 先确定有足够大的空间
        assert(len != 0);
        EnsureWriteSpace(len);
        const char *d = (const char *)data;
        std::copy(d, d + len, GetWritePosition());
    }
    void WriteAndPush(const void *data, uint64_t len)
    {
        Write(data, len);
        MoveWriteOffset(len);
    }
    void WriteString(const string &str)
    {
        Write(str.c_str(), str.size());
    }
    void WriteStringAndPush(const string &str)
    {
        Write(str.c_str(), str.size());
        MoveWriteOffset(str.size());
    }
    void WriteBuffer(Buffer &buf)
    {
        Write(buf.GetReadPosition(), buf.GetReadAbleSize());
    }
    void WriteBufferAndPush(Buffer &buf)
    {
        WriteBuffer(buf);
        MoveReadOffset(buf.GetReadAbleSize());
    }
    void Read(void *buf, uint64_t len)
    {
        assert(len <= GetReadAbleSize());
        std::copy(GetReadPosition(), GetReadPosition() + len, (char *)buf);
    }
    void ReadAndPop(void *buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }
    std::string ReadAsString(uint64_t len)
    {
        assert(len <= GetReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len);
        return str;
    }
    std::string ReadAsStringAndPop(uint64_t len)
    {
        assert(len <= GetReadAbleSize());
        string str = ReadAsString(len);
        MoveReadOffset(len);
        return str;
    }
    char *FindCRLF()
    {
        char *res = (char *)memchr(GetReadPosition(), '\n', GetReadAbleSize());
        return res;
    }
    std::string GetLine()
    {
        char *pos = FindCRLF();
        if (pos == NULL)
        {
            return "";
        }
        // +1是为了把换行字符也取出来。
        return ReadAsString(pos - GetReadPosition() + 1);
    }
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }
    // 清空缓冲区
    void Clear()
    {
        // 只需要将偏移量归0即可
        _reader_idx = 0;
        _writer_idx = 0;
    }
};